package edu.ccut.saturn.component;

import java.io.InputStream;
import java.net.URL;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;

import org.dom4j.Element;
import org.osgi.framework.Bundle;

import edu.ccut.saturn.component.impl.SaturnBundleFilterInfo;
import edu.ccut.saturn.component.impl.SaturnBundleInfo;
import edu.ccut.saturn.component.impl.SaturnDataDictTypeInfo;
import edu.ccut.saturn.component.impl.SaturnDictItemInfo;
import edu.ccut.saturn.component.impl.SaturnLogicContext;
import edu.ccut.saturn.component.impl.SaturnParameter;
import edu.ccut.saturn.component.impl.SaturnParameterContext;
import edu.ccut.saturn.component.impl.directory.SaturnResourceFactory;
import edu.ccut.saturn.component.loader.AuthorityLoader;
import edu.ccut.saturn.component.loader.ComponentLoader;
import edu.ccut.saturn.component.loader.DatabaseConfigLoader;
import edu.ccut.saturn.component.loader.DirectoryInfoLoader;
import edu.ccut.saturn.component.loader.FilterInfoLoader;
import edu.ccut.saturn.component.loader.MenuInfoLoader;
import edu.ccut.saturn.component.loader.SaturnDataLoader;
import edu.ccut.saturn.component.loader.ValidateLoader;
import edu.ccut.saturn.component.loader.WorkFlowLoader;

/**
 * 创建组件相关对象的工厂类，并暴露方法给其它工程使用。
 * 
 * @author 谷钰
 * @author 温建
 * 
 * @version 1.0 2008.9.03
 * 
 */
// TODO:类的作用？component工程只暴露了一个接口包，这个工厂方法可以调用其它没有被暴露的包中的方法并返回执行结果
public abstract class ComponentFactory {

	/**
	 * 获得bundle根路径下所有的资源信息，包括路径资源和文件资源
	 * 
	 * @param bundle
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static List<IResourceInfo> getDirectoryInfos(Bundle bundle) {
		List<IResourceInfo> resourceInfos = new LinkedList<IResourceInfo>();

		// 判断是否是用felix的OSGi实现对jar包进行搜索,如果是子文件夹则以“/”结尾
		if (isFelixFrameWork(bundle)) {
			Enumeration<String> paths = bundle.getEntryPaths("/");

			while (paths.hasMoreElements()) {
				String path = paths.nextElement();

				if (path.endsWith("/")) {
					URL directoryInfoURL = bundle.getEntry(path
							+ IDirectoryInfo.SATURN_DIRECTORY_INFO_NAME);

					String directoryConfigPath = path
							+ IDirectoryInfo.SATURN_DIRECTORY_INFO_NAME;

					if (directoryInfoURL != null) {
						addDirectoryInfo(bundle, resourceInfos,
								directoryConfigPath);
					}

				} else if (isValidConfigResource(path)) {
					addFileResourceInfo(resourceInfos, path, null);
				}
			}
		}
		// 下面是用eclipse的OSGi实现对工程进行搜索，搜索的子文件夹和文件一样，没有后缀“/”
		else {
			Enumeration<URL> directoryConfigPaths = bundle.findEntries("/src",
					IDirectoryInfo.SATURN_DIRECTORY_INFO_NAME, true);

			while (directoryConfigPaths.hasMoreElements()) {
				URL path = directoryConfigPaths.nextElement();
				addDirectoryInfo(bundle, resourceInfos, path.getPath());
			}
			Enumeration<URL> configFilePaths = bundle.findEntries("/src",
					"*.config", true);

			while (configFilePaths.hasMoreElements()) {
				URL path = configFilePaths.nextElement();
				String pathStr = path.getPath();
				int index = pathStr.lastIndexOf("/");
				String directoryPath = pathStr.substring(0, index);
				String fileName = pathStr.substring(index + 1);
				addFileResourceInfo(resourceInfos, fileName, directoryPath);
			}
		}
		return resourceInfos;
	}

	/**
	 * 获得指定路径下的所有资源信息
	 * 
	 * @param bundle
	 * @param root
	 * @return
	 */
	// TODO:上面方法是不是应该被合并到这个方法
	@SuppressWarnings("unchecked")
	public static List<IResourceInfo> getDirectoryInfos(Bundle bundle,
			String root) {

		if (root == null || "".equals(root)) {
			root = "/";
		}

		List<IResourceInfo> resourceInfos = new LinkedList<IResourceInfo>();

		// 判断是否是用felix的OSGi实现对jar包进行搜索,如果是子文件夹则以“/”结尾
		if (isFelixFrameWork(bundle)) {
			Enumeration<String> paths = bundle.getEntryPaths(root);

			while (paths.hasMoreElements()) {
				String path = paths.nextElement();

				if (path.endsWith("/")) {
					URL directoryInfoURL = bundle.getEntry(path
							+ IDirectoryInfo.SATURN_DIRECTORY_INFO_NAME);

					String directoryConfigPath = path
							+ IDirectoryInfo.SATURN_DIRECTORY_INFO_NAME;

					if (directoryInfoURL != null) {
						addDirectoryInfo(bundle, resourceInfos,
								directoryConfigPath);
					}

				} else if (isValidConfigResource(path)) {
					addFileResourceInfo(resourceInfos, path, null);
				}
			}
		}
		// 下面是用eclipse的OSGi实现对工程进行搜索，搜索的子文件夹和文件一样，没有后缀“/”
		else {
			Enumeration<URL> directoryConfigPaths = bundle.findEntries("/src",
					IDirectoryInfo.SATURN_DIRECTORY_INFO_NAME, true);

			while (directoryConfigPaths.hasMoreElements()) {
				URL path = directoryConfigPaths.nextElement();
				addDirectoryInfo(bundle, resourceInfos, path.getPath());
			}
			Enumeration<URL> configFilePaths = bundle.findEntries("/src",
					"*.config", true);

			while (configFilePaths.hasMoreElements()) {
				URL path = configFilePaths.nextElement();
				String pathStr = path.getPath();
				int index = pathStr.lastIndexOf("/");
				String directoryPath = pathStr.substring(0, index);
				String fileName = pathStr.substring(index + 1);
				addFileResourceInfo(resourceInfos, fileName, directoryPath);
			}
		}
		return resourceInfos;
	}

	private static void addFileResourceInfo(List<IResourceInfo> resourceInfos,
			String fileName, String directoryPath) {

		try {
			IResourceInfo resourceInfo = SaturnResourceFactory.getInstance()
					.createFileResource(directoryPath, fileName);

			resourceInfos.add(resourceInfo);

		} catch (SaturnComponentException e) {
			e.printStackTrace();
		}
	}

	private static void addDirectoryInfo(Bundle bundle,
			List<IResourceInfo> resourceInfos, String path) {

		IDirectoryInfo directoryInfo = null;

		try {
			directoryInfo = ComponentFactory.getDirectoryInfo(bundle, path);
			resourceInfos.add(directoryInfo);

		} catch (SaturnComponentException e) {
			e.printStackTrace();
		}
	}

	@SuppressWarnings("unchecked")
	private static void addDirectoryInfoByLazyLoader(Bundle bundle,
			List<IResourceInfo> resourceInfos, String path) {

		IDirectoryInfo directoryInfo = null;

		try {
			directoryInfo = ComponentFactory.getDirectoryInfo(bundle, path);

			if (directoryInfo != null && directoryInfo.getType() != null) {

				if (IDirectoryInfo.SATURN_DIRECTORY_TYPE_WEB
						.equals(directoryInfo.getType())) {

					resourceInfos.add(directoryInfo);

				} else if (IDirectoryInfo.SATURN_DIRECTORY_TYPE_DATA
						.equals(directoryInfo.getType())) {

					resourceInfos.add(directoryInfo);

				} else if (IDirectoryInfo.SATURN_DIRECTORY_TYPE_VALIDATE
						.equals(directoryInfo.getType())) {

					resourceInfos.add(directoryInfo);

				} else if (IDirectoryInfo.SATURN_DIRECTORY_TYPE_WORKFLOW
						.equals(directoryInfo.getType())) {

					resourceInfos.add(directoryInfo);

				} else if (IDirectoryInfo.SATURN_DIRECTORY_TYPE_MODULE
						.equals(directoryInfo.getType())) {

					Enumeration<String> paths = bundle
							.getEntryPaths(directoryInfo.getDirectoryPath());

					while (paths.hasMoreElements()) {
						String pathName = paths.nextElement();

						if (pathName.endsWith("/")) {

							addDirectoryInfoByLazyLoader(
									bundle,
									resourceInfos,
									pathName
											+ IDirectoryInfo.SATURN_DIRECTORY_INFO_NAME);
						}

					}
				}
			}

		} catch (SaturnComponentException e) {
			e.printStackTrace();
		}
	}

	private static boolean isFelixFrameWork(Bundle bundle) {

		if ("org.apache.felix.framework.BundleImpl".equals(bundle.getClass()
				.getName())) {

			return true;
		}
		return false;
	}

	private static boolean isValidConfigResource(String path) {

		if (path.equals(IFileResourceInfo.SATURN_CONFIG_NAME_AUTHORITY)) {
			return true;

		} else if (path.equals(IFileResourceInfo.SATURN_CONFIG_NAME_MENU)) {
			return true;

		} else if (path.equals(IFileResourceInfo.SATURN_CONFIG_NAME_DATABASE)) {
			return true;
			
		} else if (path.equals(IFileResourceInfo.SATURN_CONFIG_NAME_Filter)) {
			return true;
			
		}
		return false;
	}

	/**
	 * 创建<code>IBundleInfo</code>类型实例，描述bundle内的加载信息
	 * 
	 * @param bundle
	 * @return
	 */
	public static IBundleInfo createBundleComponentInfo(Bundle bundle) {
		return new SaturnBundleInfo(bundle.getSymbolicName());
	}

	/**
	 * 创建<code>IParameter</code>类型实例，通过参数值和参数类型创建
	 * 
	 * @param value
	 * @param classType
	 * @return
	 */
	public static IParameter createParameter(Object value, Class<?> classType) {
		return new SaturnParameter(value, classType);
	}

	/**
	 * 创建一个没有任何参数信息的参数上下文对象
	 * 
	 * @return
	 */
	public static IParameterContext createParameterContext() {
		return new SaturnParameterContext();
	}

	/**
	 * 创建<code>ILogicContext</code>类型的实例
	 * 
	 * @param id
	 * @return
	 */
	public static ILogicContext createLogicContext(String id) {
		return new SaturnLogicContext(id);
	}

	/**
	 * 从component组件配置文件加载component组件信息 component组件配置文件是以“.component”为后缀的。
	 * 
	 * @param bundle
	 * @param filePath
	 * @return
	 * @throws SaturnComponentException
	 *             加载失败会抛出此异常
	 */
	public static IComponentInfo getComponentInfos(Bundle bundle,
			String filePath) throws SaturnComponentException {

		return ComponentLoader.loadBaseComponent(bundle, filePath);
	}

	/**
	 * 从输入流对象加载component组件信息。
	 * 
	 * @param bundle
	 * @param in
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IComponentInfo getComponentInfos(Bundle bundle, InputStream in)
			throws SaturnComponentException {

		return ComponentLoader.loadBaseComponent(bundle, in);
	}
	
	/**
	 * 从路径描述文件中加载路径资源信息。 路径描述文件是文件夹内部的一个配置文件，以“.saturn”为后缀。
	 * <p>
	 * In general, file name is ".saturn"
	 * 
	 * @param bundle
	 * @param filePath
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IDirectoryInfo getDirectoryInfo(Bundle bundle, String filePath)
			throws SaturnComponentException {

		return DirectoryInfoLoader.loadDirectoryInfo(bundle, filePath);
	}

	/**
	 * 从logic组件配置文件中加载logic组件信息。 logic组件配置文件是以“.logic”为后缀的xml格式的配置文件。
	 * 
	 * @param bundle
	 * @param filePath
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IComponentInfo getLogicComponentInfo(Bundle bundle,
			String filePath) throws SaturnComponentException {

		return ComponentLoader.loadLogicComponentInfo(bundle, filePath);
	}

	/**
	 * 从输入流对象中加载logic组件信息.
	 * 
	 * @param bundle
	 * @param in
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IComponentInfo getLogicComponentInfo(Bundle bundle,
			InputStream in) throws SaturnComponentException {

		return ComponentLoader.loadLogicComponentInfo(bundle, in);
	}

	/**
	 * 从action组件配置文件中加载action组件信息。 action组件配置文件是以“.action”为后缀的xml格式的配置文件。
	 * 
	 * @param bundle
	 * @param filePath
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IComponentInfo getActionComponentInfo(Bundle bundle,
			String filePath) throws SaturnComponentException {

		return ComponentLoader.loadActionComponentInfo(bundle, filePath);
	}

	/**
	 * 从输入流对象中加载action组件信息.
	 * 
	 * @param bundle
	 * @param in
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IComponentInfo getActionComponentInfo(Bundle bundle,
			InputStream in) throws SaturnComponentException {

		return ComponentLoader.loadActionComponentInfo(bundle, in);
	}

	/**
	 * 获得验证组件的信息
	 * 
	 * @param bundle
	 * @param in
	 * @return
	 * @throws ClassNotFoundException
	 * @throws SaturnComponentException
	 */
	public static IValidateInfo getValidateInfo(Bundle bundle, InputStream in)
			throws ClassNotFoundException, SaturnComponentException {

		return ValidateLoader.loadValidateInfo(bundle, in);
	}

	/**
	 * 获得验证组件的信息
	 * 
	 * @param bundle
	 * @param filePath
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IValidateInfo getValidateInfo(Bundle bundle, String filePath)
			throws SaturnComponentException {

		return ValidateLoader.loadValidateInfo(bundle, filePath);
	}

	/**
	 * 获得应用验证组件的信息
	 * 
	 * @param bundle
	 * @param validates
	 * @return
	 * @throws ClassNotFoundException
	 */
	public static IValidateUseInfo getValidateUseInfo(Bundle bundle,
			Element validates) throws ClassNotFoundException {

		return ValidateLoader.loadValidateUseInfo(bundle, validates);
	}

	/**
	 * 获得数据字典信息
	 * 
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IDataDictTypeInfo createIDataDictTypeInfo()
			throws SaturnComponentException {

		return new SaturnDataDictTypeInfo();
	}

	/**
	 * 根据数据字典实例创建数据字典信息
	 * 
	 * @param dataDictTypeInfo
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IDataDictTypeInfo createSaturnDataDictTypeInfo(
			IDataDictTypeInfo dataDictTypeInfo) throws SaturnComponentException {

		return new SaturnDataDictTypeInfo(dataDictTypeInfo);
	}

	// TODO:没用
	public static IDictItemInfo createIDictItemInfo()
			throws SaturnComponentException {

		return new SaturnDictItemInfo();
	}

	/**
	 * 获得工作流配置文件信息
	 * 
	 * @param bundle
	 * @param workFlowFile
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IWorkFlowInfo getWorkFlowInfo(Bundle bundle,
			String workFlowFile) throws SaturnComponentException {

		return WorkFlowLoader.loadWorkFlowInfo(bundle, workFlowFile);
	}

	/**
	 * 获得权限配置文件信息
	 * 
	 * @param bundle
	 * @param url
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IBundleAuthorityInfo getAuthorityInfo(Bundle bundle, URL url)
			throws SaturnComponentException {

		return AuthorityLoader.loadAuthorityInfo(bundle, url);
	}

	/**
	 * 加载数据库连接池配置文件信息
	 * 
	 * @param bundle
	 * @param url
	 * @return
	 * @throws SaturnComponentException
	 */
	public static IDatabaseConfigInfo getDatabaseConfigInfo(Bundle bundle,
			URL url) throws SaturnComponentException {

		return DatabaseConfigLoader.loadDatabaseConfigInfo(bundle, url);
	}

	/**
	 * 加载菜单配置文件信息
	 * 
	 * @param bundle
	 * @param url
	 * @return
	 * @throws SaturnComponentException
	 */
	public static List<IMuneItemInfo> loadMenuInfo(Bundle bundle, URL url)
			throws SaturnComponentException {

		return MenuInfoLoader.loadSaturnMenuItemInfos(bundle, url);
	}

	/**
	 * 从输入流对象中加载数据项组件信息
	 * 
	 * @param bundle
	 * @param in
	 * @return
	 * @throws Exception
	 */
	public static IDataInfo getDataInfo(Bundle bundle, InputStream in)
			throws Exception {

		return SaturnDataLoader.loadDataInfo(bundle, in);
	}

	@SuppressWarnings("unchecked")
	public static List<IResourceInfo> getDirectoryInfosByLazyLoader(
			Bundle bundle) {

		List<IResourceInfo> resourceInfos = new LinkedList<IResourceInfo>();

		// 判断是否是用felix的OSGi实现对jar包进行搜索,如果是子文件夹则以“/”结尾
		if (isFelixFrameWork(bundle)) {
			Enumeration<String> paths = bundle.getEntryPaths("/");

			while (paths.hasMoreElements()) {
				String path = paths.nextElement();

				if (path.endsWith("/")) {

					URL directoryInfoURL = bundle.getEntry(path
							+ IDirectoryInfo.SATURN_DIRECTORY_INFO_NAME);

					String directoryConfigPath = path
							+ IDirectoryInfo.SATURN_DIRECTORY_INFO_NAME;

					if (directoryInfoURL != null) {
						addDirectoryInfoByLazyLoader(bundle, resourceInfos,
								directoryConfigPath);
					}

				} else if (isValidConfigResource(path)) {
					addFileResourceInfo(resourceInfos, path, null);
				}
			}
		}
		// 下面是用eclipse的OSGi实现对工程进行搜索，搜索的子文件夹和文件一样，没有后缀“/”
		else {
			Enumeration<URL> directoryConfigPaths = bundle.findEntries("/src",
					IDirectoryInfo.SATURN_DIRECTORY_INFO_NAME, true);

			while (directoryConfigPaths.hasMoreElements()) {
				URL path = directoryConfigPaths.nextElement();
				addDirectoryInfoByLazyLoader(bundle, resourceInfos, path
						.getPath());
			}
			Enumeration<URL> configFilePaths = bundle.findEntries("/src",
					"*.config", true);

			while (configFilePaths.hasMoreElements()) {
				URL path = configFilePaths.nextElement();
				String pathStr = path.getPath();
				int index = pathStr.lastIndexOf("/");
				String directoryPath = pathStr.substring(0, index);
				String fileName = pathStr.substring(index + 1);
				addFileResourceInfo(resourceInfos, fileName, directoryPath);
			}
		}
		return resourceInfos;
	}

	public static IComponentInfo getComponentInfoByKey(Bundle bundle,
			String componentKey) throws SaturnComponentException {

		if (componentKey.endsWith(".action")) {
			return getActionComponentInfo(bundle, componentKey);

		} else if (componentKey.endsWith(".logic")) {
			return getLogicComponentInfo(bundle, componentKey);

		} else if (componentKey.endsWith(".component")) {
			return getComponentInfos(bundle, componentKey);
		} 
		
		return null;
	}
	
	/**
	 * 获得过滤器配置文件信息
	 * @param bundle
	 * @param url
	 * @return
	 * @throws SaturnComponentException
	 */
	public static SaturnBundleFilterInfo getSaturnBundleFilterInfo(Bundle bundle, 
			URL url) throws SaturnComponentException{
		return FilterInfoLoader.loadSaturnBundleFilterInfo(bundle, url);
	}
}
